﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class provides the scanning or sampling of a polynomial.
    /// </summary>
    [Serializable]
    public class PolynomialSampler : AbstractPolynomialSampler
    {
        /// <summary>
        /// The polynomial to scan.
        /// </summary>
        private Polynomial polynomial;

        /// <summary>
        /// Initializes a new instance of the <see cref="PolynomialSampler"/> class.
        /// </summary>
        /// <param name="polynomial">The polynomial to scan or sample.</param>
        public PolynomialSampler(Polynomial polynomial)
        {
            this.polynomial = polynomial;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="PolynomialSampler"/> class.
        /// </summary>
        /// <param name="polynomial">The polynomial to scan or sample.</param>
        public PolynomialSampler(SimplePolynomial polynomial)
        {
            if (polynomial == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("polynomial");
            }

            this.polynomial = polynomial.ToPolynomial();
        }

        /// <summary>
        /// Gets or sets the polynomial to sample or scan.
        /// </summary>
        /// <value>The polynomial to sample or scan.</value>
        public Polynomial Polynomial
        {
            get { return polynomial; }
            set { polynomial = value; }
        }

        /// <summary>
        /// Samples or scans the polynomial in an specified interval.
        /// </summary>
        /// <param name="startValue">The start value of the sample process.</param>
        /// <param name="endValue">The end value of the sample process.</param>
        /// <param name="interval">The interval for the sampling process.</param>
        /// <returns>
        /// The results of the sampling process in form of plane points.
        /// </returns>
        public Point2D[] SamplePolynomial(double startValue, double endValue, double interval)
        {
            if (endValue < startValue)
            {
                Swap(ref startValue, ref endValue);
            }

            int numberOfSamples = ((int) ((endValue - startValue) / interval)) + 1;
            double currentSampleValue = startValue;
            double samplerate = (endValue - startValue) / (numberOfSamples - 1);
            Point2D[] result = new Point2D[numberOfSamples];

            for (int i = 0; i < numberOfSamples; i++)
            {
                result[i] = new Point2D(currentSampleValue, this.polynomial.SolveAt(currentSampleValue));
                currentSampleValue += samplerate;
            }

            return result;
        }

        /// <summary>
        /// Swaps the specified values.
        /// </summary>
        /// <param name="a">The first value to swap.</param>
        /// <param name="b">The second value to swap.</param>
        private static void Swap(ref double a, ref double b)
        {
            double tempuri = a;

            a = b;
            b = tempuri;
        }
    }
}